home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Freelog Special Freeware 31
/
FreelogHS31.iso
/
ArgentCompta
/
Bankperfect
/
bp.exe
/
Scripts
/
Import QIF
/
import_qif.py
< prev
Wrap
Text File
|
2007-03-25
|
15KB
|
364 lines
#1.5
import BP
d = {}
ko = "└┴┬├─┼╞╟╚╔╩╦╠═╬╧╤╥╙╘╒╓┘┌█▄▌▀αßΓπΣσµτΦΘΩδ∞φε∩±≥≤⌠⌡÷∙·√ⁿ² ABCDEFGHIJKLMNOPQRSTUVWXYZ"
ok = "aaaaaaaceeeeiiiinooooouuuuybaaaaaaaceeeeiiiinooooouuuuyyabcdefghijklmnopqrstuvwxyz"
[d.setdefault(a, b) for a, b in zip(ko, ok)]
PatternTable = "".join([d.get(chr(i), chr(i)) for i in range(256)])
CIndexes = {}
CtgPatt = []
def Pattern(v):
return v.translate(PatternTable, " -.,;:/!?'_=")
def DoIndexCategs():
global CIndexes, CtgPatt
CIndexes = {}
for i, c in enumerate(BP.CategName):
CIndexes[i] = int(c[:c.find("=")])
CtgPatt = [Pattern(c) for c in BP.CategName]
DoIndexCategs()
Acc = BP.AccountCurrent()
l, b, a, cc = "TLabel", "TButton", ["akBottom", "akRight"], CreateComponent
DtFmts = ["JMA", "MJA", "AMJ"]
FDup = cc("TForm", None)
FDup.SetProps(Width=400, Height=390, Position="poMainFormCenter", BorderStyle="bsSingle", BorderIcons=["biSystemMenu"], Caption="DΘtection de doublons")
l0 = cc(l, FDup)
l0.SetProps(Parent=FDup, Left=20, Top=20)
l1 = cc(l, FDup)
l1.SetProps(Parent=FDup, Left=20, Top=60, Caption="Ligne α insΘrer :")
l2 = cc(l, FDup)
l2.SetProps(Parent=FDup, Left=20, Top=190, Caption="Ligne existante :")
l0.Font.Style = l1.Font.Style = l2.Font.Style = ["fsBold"]
cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=80, Caption="Date :")
cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=100, Caption="Mode :")
cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=120, Caption="Tiers :")
cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=140, Caption="DΘtails :")
cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=160, Caption="Montant :")
cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=210, Caption="Date :")
cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=230, Caption="Mode :")
cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=250, Caption="Tiers :")
cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=270, Caption="DΘtails :")
cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=290, Caption="Montant :")
lD = cc(l, FDup)
lD.SetProps(Parent=FDup, Left=120, Top=80)
lM = cc(l, FDup)
lM.SetProps(Parent=FDup, Left=120, Top=100)
lT = cc(l, FDup)
lT.SetProps(Parent=FDup, Left=120, Top=120)
lI = cc(l, FDup)
lI.SetProps(Parent=FDup, Left=120, Top=140)
lA = cc(l, FDup)
lA.SetProps(Parent=FDup, Left=120, Top=160)
LD = cc(l, FDup)
LD.SetProps(Parent=FDup, Left=120, Top=210)
LM = cc(l, FDup)
LM.SetProps(Parent=FDup, Left=120, Top=230)
LT = cc(l, FDup)
LT.SetProps(Parent=FDup, Left=120, Top=250)
LI = cc(l, FDup)
LI.SetProps(Parent=FDup, Left=120, Top=270)
LA = cc(l, FDup)
LA.SetProps(Parent=FDup, Left=120, Top=290)
lD.Font.Color = lM.Font.Color = lT.Font.Color = lI.Font.Color = lA.Font.Color = LD.Font.Color = LM.Font.Color = LT.Font.Color = LI.Font.Color = LA.Font.Color = 0x00CC0000
cc(b, FDup).SetProps(Parent=FDup, Left=40, Top=320, Width=75, Height=25, Caption="Oui", ModalResult=6)
cc(b, FDup).SetProps(Parent=FDup, Left=120, Top=320, Width=75, Height=25, Caption="Non", ModalResult=7)
cc(b, FDup).SetProps(Parent=FDup, Left=200, Top=320, Width=75, Height=25, Caption="Toutes", ModalResult=10)
cc(b, FDup).SetProps(Parent=FDup, Left=280, Top=320, Width=75, Height=25, Caption="Aucune", ModalResult=9)
def CheckPos(Sender):
CCtgs.Top = F0.Height - 70
F0 = cc("TForm", None)
F0.SetProps(Position = "poMainFormCenter", Width=600, Height=320, Caption = "ParamΦtres de l'import", OnShow=CheckPos)
F0.Constraints.MinWidth = 600
cc(l, F0).SetProps(Parent=F0, Left=16, Top=20, Caption="Sens de la date :")
cc(l, F0).SetProps(Parent=F0, Left=160, Top=20, Caption="Doublons :")
cc(l, F0).SetProps(Parent=F0, Left=276, Top=20, Caption="Contenu du fichier :")
CBDate = cc("TComboBox", F0)
CBDate.SetProps(Parent=F0, Left=16, Top=39, Width=93, Style="csDropDownList")
CBDate.Items.Text = "\n".join(DtFmts)
CBDate.ItemIndex = 0
CBDup = cc("TComboBox", F0)
CBDup.SetProps(Parent=F0, Left=160, Top=39, Width=100, Style="csDropDownList")
CBDup.Items.Text = "Tout accepter\nTout refuser\nDemander"
CBDup.ItemIndex = 2
Memo = cc("TMemo", F0)
Memo.SetProps(Parent=F0, Left=276, Top=40, Width=293, Height=89, WordWrap=1, Anchors=a+["akTop","akLeft"])
CCtgs = cc("TCheckBox", F0)
CCtgs.SetProps(Parent=F0, Left=16, Top=300, Width=213, Caption="CrΘer les catΘgories manquantes", Anchors=["akLeft", "akBottom"])
BKO = cc(b, F0)
BKO.SetProps(Parent=F0, Left=415, Top=300, Width=75, Height=25, Caption="Annuler", ModalResult=2, Cancel=1, Anchors=a)
BOK = cc(b, F0)
BOK.SetProps(Parent=F0, Left=495, Top=300, Width=75, Height=25, Caption="Suivant >>", ModalResult=1, Default=1, Anchors=a)
FF = cc("TForm", None)
FF.SetProps(Width=640, Height=450, Position="poMainFormCenter", BorderStyle="bsSingle", BorderIcons=["biSystemMenu"], Caption="RΘsultat de l'import")
cc(b, FF).SetProps(Parent=FF, Left=270, Top=370, Width=100, Height=25, Caption="Fermer", ModalResult=1, Cancel=1, Default=1)
MRes = cc("TMemo", FF)
MRes.SetProps(Parent=FF, Left=30, Top=30, Width=580, Height=350, Anchors=["akTop","akLeft", "akRight", "akBottom"], WordWrap=0, Readonly=1)
FF.Font.Name = F0.Font.Name = FDup.Font.Name = "Tahoma"
def GetCtg(s):
if s.strip() == "": return -1
t = Pattern(s)
if t.strip() == "": return -1
if t in CtgPatt: return CIndexes.get(CtgPatt.index(t), -1)
for i in range(len(CtgPatt)):
c = CtgPatt[i]
if t in c or c in t: return CIndexes.get(i, -1)
if CCtgs.Checked:
BP.CategAdd(s, 0)
DoIndexCategs()
return CIndexes.get(BP.CategCount() - 1, -1)
return -1
def getmode(s, sign):
s = s.strip()
if s != "":
if sign == -1 and s.isdigit(): return "Chq %s" %s
v = Pattern(s)
if sign == 1: fmodes = {"Versement": ["vers", "esp"], "DΘp⌠t de chΦque": ["rem", "dep", "ch"], "Virement reτu": ["vir", "vrm", "vrt"]}
else: fmodes = {"Carte": ["fac", "cb", "car"], "Retrait DAB": ["ret", "dab", "distrib", "automat"], "ChΦque Θmis": ["ch"], "PrΘlΦvement": ["pr"], "Virement Θmis": ["vir", "vrm", "vrt"], "TIP": ["tip"]}
for m in fmodes.keys():
fpatterns = fmodes[m]
for fpattern in fpatterns:
if v.find(fpattern) == 0:
if m == "ChΦque Θmis":
v = s.split(" ")[-1].split(".")[-1].split("░")[-1].split("Q")[-1].split("E")[-1].split("H")[-1]
if v.isdigit(): return "Chq %s" %v
return m
if sign == 1: return "Virement reτu"
return "PrΘlΦvement"
def getprefixes(L):
d = {}
for l in L:
if len(l) > 0 and l[0] in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
d[l[0]] = 1
r = d.keys()
r.sort()
return r
def AddCombos(prefixes):
c = "\n".join(["--------", "Date", "Mode", "Tiers", "DΘtails", "CatΘgorie", "Montant"])
f = []
for i, p in enumerate(prefixes):
top = 84 + i * 26
cc("TLabel", F0).SetProps(Parent=F0, Left=16, Top=top+4, Caption="La lettre %s prΘcΦde le champ" %p)
cb = cc("TComboBox", F0)
cb.SetProps(Parent=F0, Left=160, Top=top, Width=100, Style="csDropDownList")
cb.Items.Text = c
cb.ItemIndex = "DNPMLT".find(p) + 1
f.append(cb)
return f
def strtodate(d):
seps = "/-' .;"
d = d.replace("-", "/").replace(".", "/").replace("'", "/").replace(" ", "").split("/")
if len(d) != 3 or not "".join(d).isdigit(): return None
d = [int(d[0]), int(d[1]), int(d[2])]
if DtFmt == "JMA": return (d[2], d[1], d[0])
elif DtFmt == "MJA": return (d[2], d[0], d[1])
elif DtFmt == "AMJ": return (d[0], d[1], d[2])
elif DtFmt == "AJM": return (d[0], d[2], d[1])
else: return None
def strtofloat(s):
s = s.replace("$", "").replace(" ", "").replace("Ç", "").replace("F", "").replace(",", ".")
if "." in s:
l = s.split(".")
s = "%s.%s" %( "".join(l[:-1]), l[-1] )
try:
f = float(s)
except:
return None
return f
def linestodic(lines, mapping):
fields = ["Date", "Mode", "Tiers", "DΘtails", "CatΘgorie", "Montant"]
result = {}
sgn = 0
for line in lines:
i = mapping[line[0]]
if i > 0:
field = fields[i - 1]
value = line[1:]
if field == "Date":
value = strtodate(value)
if value is None: return None
elif field == "CatΘgorie": value = GetCtg(value)
elif field == "Montant":
value = strtofloat(value)
if value == None: return None
if value > 0: sgn = 1
elif value < 0: sgn = -1
result[field] = value
try:
if sgn != 0: result["Mode"] = getmode(result.get("Mode", ""), sgn)
except:
pass
return result
def divide(lines, mapping):
res = []
MinDate = (3000, 12, 31)
rep = {"OpΘrations importΘes" : [], "Dates incorrectes" : [], "Montants incorrects" : [], "Enregistrements incorrects" : [], "Lignes refusΘes" : [], "Doublons" : []}
while lines.count("^") > 0:
i = lines.index("^")
r = linestodic(lines[:i], mapping)
if r != None:
if not r.has_key("Date"): rep["Dates incorrectes"].append(", ".join(lines[:i]))
elif not r.has_key("Montant"): rep["Montants incorrects"].append(", ".join(lines[:i]))
else:
y, m, d = r["Date"]
if y < 100: y += 2000
r["Date"] = (y, m, d)
if (y, m, d) < MinDate: MinDate = (y, m, d)
res.append(r)
else: rep["Enregistrements incorrects"].append(", ".join(lines[:i]))
del lines[:i + 1]
return res, rep, MinDate
def FlatCheck(m, t, i):
if m == "ChΦque Θmis" and i != "":
num = t.split("░")[-1].split(" ")[-1]
if num.isdigit(): m = "Chq %s" %num
else:
num = i.split("░")[-1].split(" ")[-1]
if num.isdigit(): m = "Chq %s" %num
if m.find("Chq ") == 0:
if i == "": i = "n░%s" %(m[4:])
else: i = "n░%s %s" %(m[4:], i)
m = "ChΦque Θmis"
return m, t, i
def ReportErrors(R):
ok = 0
ko = 0
L = []
for key in R.keys():
l = R[key]
num = len(l)
if num == 0: continue
if key == "OpΘrations importΘes": ok += num
else: ko += num
l = [" %s" %s for s in l]
L.append("%s (%d) :\r\n\r\n%s" %(key, num, "\r\n".join(l)))
T = ok + ko
if T == 0:
s = "Il n'y a aucune ligne α importer depuis le fichier"
else:
if ko == 0:
if T == 1: s = "L'opΘration contenue dans le fichier QIF a ΘtΘ importΘe sans erreurs"
else: s = "Les %d opΘrations contenues dans le fichier QIF ont ΘtΘ importΘes sans erreurs" %T
elif ok == 0: s = "Aucune ligne n'a pu Ωtre importΘe"
else:
if ok == 1: s = "Une opΘration sur %d a ΘtΘ importΘe" %(T)
else: s = "%d opΘrations sur %d ont ΘtΘ importΘes" %(ok, T)
s = "%s\r\n\r\n%s" %(s, "\r\n\r\n".join(L))
return s
def IsDate(t):
try:
y, m, d = t
if (m == 2) and (y % 4 == 0) and ( (y % 100 != 0) or (y % 400 == 0) ): Max = 29
else: Max = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][m - 1]
return m > 0 and m < 13 and d > 0 and d <= Max
except:
return 0
def FormatLine(dic):
s = []
for key in dic:
v = dic[key]
if key == "Date": v = datetostr(v)
s.append("%s : %s" %(key, v))
s.sort()
return ", ".join(s)
def datetostr(d):
y, m, d = d
if y < 100: y += 2000
return "%02d/%02d/%04d" %(d, m, y)
def TestDup(N, T, Rep, ask, Lines, Light, R, d, m, v):
if ask == 0: res = "ok", ask
elif not (d, m, v) in Light: res = "ok", ask
elif ask == 1: res = "ko", ask
else:
i = Light.index((d, m, v))
l = Lines[i]
lD.Caption, lM.Caption, lT.Caption, lI.Caption, lA.Caption = datetostr(R[0]), R[1], R[2], R[3], R[4]
LD.Caption, LM.Caption, LT.Caption, LI.Caption, LA.Caption = datetostr(l[0]), l[1], l[3], l[4], l[2]
l0.Caption = "La ligne %d/%d ressemble α une ligne existante.\nSouhaitez-vous l'insΘrer ?" %(N, T)
i = FDup.ShowModal()
res = {2: ("ko", ask), 6: ("ok", ask), 10: ("ok", 0), 7: ("ko", ask), 9: ("ko", 1)}[i]
if res[0] == "ko": Rep["Doublons"].append(line)
return res
def simplecheck(s):
return [s, "ChΦque Θmis"][s.find("Chq") == 0]
def GetLines(From):
l1 = zip(BP.OperationDate[Acc], BP.OperationMode[Acc], BP.OperationAmount[Acc], BP.Operationthirdparty[Acc], BP.OperationDetails[Acc])
l1 = [((int(d[6:10]), int(d[3:5]), int(d[0:2])), m, v, w, i) for (d, m, v, w, i) in l1 if (int(d[6:10]), int(d[3:5]), int(d[0:2])) >= From]
l2 = [(l[0], simplecheck(l[1]), l[2]) for l in l1]
return l1, l2
QIFFile = BP.OpenDialog("Choisissez le fichier α importer", "\\", ".qif", "Quicken Interchange Format (*.QIF)|*.qif")
if QIFFile != "":
f = open(QIFFile).readlines()
f = [l.replace("\n", "").strip() for l in f if len(l) > 0 and l[0] in "ABCDEFGHIJKLMNOPQRSTUVWXYZ^"]
prefixes = getprefixes(f)
if len(prefixes) < 3: BP.MsgBox("Le fichier n'est pas un fichier QIF correct", 0)
else:
BP.AccountRefreshScreen()
h = 160 + 26 * len(prefixes)
Combos = AddCombos(prefixes)
Memo.Height, Memo.Lines.Text = h - 121, "\n".join(f[:50])
CCtgs.Top = BKO.Top = BOK.Top = h - 69
F0.Height = F0.Constraints.MinHeight = h
Memo.Height = h - 120
BOK.Top = h - 70
BKO.Top = h - 70
if F0.ShowModal() == 1:
dupl, DtFmt = CBDup.ItemIndex, DtFmts[CBDate.ItemIndex]
mapping = dict([(p, Combos[i].ItemIndex) for i, p in enumerate(prefixes)])
operations, report, MinDate = divide(f, mapping)
CurrLines, LinesLight = GetLines(MinDate)
i, num_ok, count_op = 0, 0, len(operations)
for op in operations:
line, i = FormatLine(op), i + 1
date, mode, tier, info, catg, mont = op.get("Date", ""), op.get("Mode", ""), op.get("Tiers", ""), op.get("DΘtails", ""), op.get("CatΘgorie", ""), op.get("Montant", "")
if not IsDate(date): report["Dates incorrectes"].append(line)
elif mont == "" or abs(mont) < 0.0001: report["Montants incorrects"].append(line)
else:
InsDup, dupl = TestDup(i, count_op, report, dupl, CurrLines, LinesLight, (date, mode, tier, info, mont), date, simplecheck(mode), mont)
if InsDup == "ko": continue
if catg == "": catg = -1
mode, tier, info = FlatCheck(mode, tier, info)
count1, date = BP.OperationCount[Acc], datetostr(date)
BP.LineAdd(Acc, date, mode, tier, info, catg, mont, 0)
count2 = BP.OperationCount[Acc]
if count2 == count1: report["Lignes refusΘes"].append(line)
else: report["OpΘrations importΘes"].append(line)
BP.AccountRefreshScreen()
MRes.Lines.Text = ReportErrors(report)
FF.ShowModal()